use super::resource::ResourceVo;
use super::Result;
use crate::entity::prelude::SysRole;
use crate::entity::{sys_resource, sys_role, sys_role_resource, sys_user, sys_user_role};
use sea_orm::{
    ActiveModelTrait, ColumnTrait, ConnectionTrait, DbConn, DerivePartialModel, EntityTrait,
    FromQueryResult, ModelTrait, PaginatorTrait, QueryFilter, QuerySelect, QueryTrait,
    RelationTrait, Set, TransactionTrait,
};
use serde::{Deserialize, Serialize};
use validator::Validate;

pub struct Role;

/// 角色列表展示的数据
#[derive(Debug, DerivePartialModel, FromQueryResult, Serialize)]
#[sea_orm(entity = "SysRole")]
pub struct RoleVo {
    pub id: i32,
    pub name: String,
    pub key: String,
    pub description: String,
    pub data_scope: i8,
    pub status: bool,
}

impl From<sys_role::Model> for RoleVo {
    fn from(value: sys_role::Model) -> Self {
        Self {
            id: value.id,
            name: value.name,
            key: value.key,
            description: value.description,
            data_scope: value.data_scope,
            status: value.status,
        }
    }
}

/// 角色简单的展示的数据
#[derive(Debug, Clone, DerivePartialModel, FromQueryResult, Deserialize, Serialize)]
#[sea_orm(entity = "SysRole")]
pub struct RoleSimpletVo {
    pub id: i32,
    pub name: String,
    pub key: String,
}

impl From<sys_role::Model> for RoleSimpletVo {
    fn from(value: sys_role::Model) -> Self {
        Self {
            id: value.id,
            name: value.name,
            key: value.key,
        }
    }
}

/// 角色提交的数据
#[derive(Debug, Deserialize, Validate)]
pub struct RoleDo {
    #[validate(length(min = 3, max = 32), non_control_character)]
    pub name: String,
    #[validate(length(min = 3, max = 32), non_control_character)]
    pub key: String,
    #[validate(length(max = 255))]
    #[serde(default)]
    pub description: String,
    pub data_scope: i8,
    pub status: bool,
}

impl Into<sys_role::ActiveModel> for RoleDo {
    fn into(self) -> sys_role::ActiveModel {
        sys_role::ActiveModel {
            name: Set(self.name),
            key: Set(self.key),
            description: Set(self.description),
            status: Set(self.status),
            data_scope: Set(self.data_scope),
            ..Default::default()
        }
    }
}

impl Role {
    /// 获取全部**可用**的角色
    pub async fn all(db: &DbConn) -> Result<Vec<RoleVo>> {
        sys_role::Entity::find()
            .filter(sys_role::Column::DelFlag.eq(0))
            .filter(sys_role::Column::Status.eq(true))
            .into_partial_model()
            .all(db)
            .await
    }

    pub async fn list(db: &DbConn, page: u64, page_size: u64) -> Result<(u64, Vec<RoleVo>)> {
        let sql = sys_role::Entity::find()
            .filter(sys_role::Column::DelFlag.eq(0))
            .into_partial_model()
            .paginate(db, page_size);
        let total = sql.num_items().await?;
        let users = sql.fetch_page(page).await?;
        Ok((total, users))
    }

    pub async fn fetch_one(db: &DbConn, id: i32) -> Result<Option<RoleVo>> {
        sys_role::Entity::find_by_id(id)
            .into_partial_model()
            .one(db)
            .await
    }

    pub async fn create(db: &DbConn, data: RoleDo) -> Result<RoleVo> {
        let mut data: sys_role::ActiveModel = data.into();
        data.del_flag = Set(0);
        data.insert(db).await.map(Into::into)
    }

    /// 根据id更新, 当id不存在时, 抛出错误
    pub async fn update(db: &DbConn, id: i32, data: RoleDo) -> Result<RoleVo> {
        let mut data: sys_role::ActiveModel = data.into();
        data.id = Set(id);
        data.update(db).await.map(Into::into)
    }

    pub async fn delete(db: &DbConn, id: i32) -> Result<sea_orm::DeleteResult> {
        let txn = db.begin().await?;
        sys_user_role::Entity::delete_many()
            .filter(sys_user_role::Column::RoleId.eq(id))
            .exec(&txn)
            .await?;
        let res = sys_role::Entity::delete_many()
            .filter(sys_role::Column::Id.eq(id))
            .exec(&txn)
            .await?;
        txn.commit().await?;
        Ok(res)
    }

    /// 获取role的全部user id
    pub async fn fetch_user<C>(db: &C, id: i32) -> Result<Vec<i32>>
    where
        C: ConnectionTrait,
    {
        sys_user::Entity::find()
            .select_only()
            .column(sys_user::Column::UserId)
            .join(
                sea_orm::JoinType::InnerJoin,
                sys_user::Relation::SysUserRole.def(),
            )
            .filter(sys_user_role::Column::RoleId.eq(id))
            .into_tuple::<i32>()
            .all(db)
            .await
    }

    /// 获取role的全部resource
    pub async fn fetch_resource<C>(db: &C, id: i32) -> Result<Vec<ResourceVo>>
    where
        C: ConnectionTrait,
    {
        sys_resource::Entity::find()
            .join(
                sea_orm::JoinType::InnerJoin,
                sys_resource::Relation::SysRoleResource.def(),
            )
            .filter(sys_role_resource::Column::RoleId.eq(id))
            .into_partial_model()
            .all(db)
            .await
    }

    /// 更新role的resource
    pub async fn update_resource<C>(db: &C, role_id: i32, resources: Vec<i32>) -> Result<()>
    where
        C: ConnectionTrait,
    {
        sys_role_resource::Entity::delete_many()
            .filter(sys_role_resource::Column::RoleId.eq(role_id))
            .exec(db)
            .await?;
        let resources = resources
            .into_iter()
            .map(|id| sys_role_resource::ActiveModel {
                role_id: Set(role_id),
                resource_id: Set(id),
            })
            .collect::<Vec<_>>();
        sys_role_resource::Entity::insert_many(resources)
            .exec(db)
            .await?;
        Ok(())
    }
}
